package com.t.bricks.bussiness.server.verifycode.impl;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.t.bricks.bussiness.model.verifycode.VerifyCodeCach;
import com.t.bricks.bussiness.model.verifycode.VerifyCodeResult;
import com.t.bricks.bussiness.server.verifycode.VerifyCodeServer;
import com.t.bricks.model.Log;
import com.t.bricks.model.MsgEmity;
import com.t.bricks.utils.function.data.SequenceUtil;
import com.t.bricks.utils.function.data.VerifyCodeUtil;

@Service
public class VerifyCodeServerImpl implements VerifyCodeServer {
	
	/**
	 * md5加密干扰串
	 */
	@Value("${app.md5.key:未设置app.md5.key配置项}")
	private String appMd5Key;
	
	/**
	 * 超时时间(秒)
	 */
	@Value("${app.verifycode.timeout:120}")
	private int timeout;
	
	/**
	 * 存储验证码对象的缓冲池
	 */
	private Map<String, VerifyCodeCach> cachMap = new ConcurrentHashMap<String, VerifyCodeCach>();
	
	/**
	 * 清理数据线程
	 * 注意:清理验证码不需要过于严谨的时间要求,差异在两分钟内都是能接受的
	 */
	@Autowired
	private void clearThread() {
		
		new Thread() {
			private int sleepTime = (timeout + 10) * 1000;//多个10秒,好处是不用过于频繁操作,同时能保证更多的情况下清理
			
			@Override
			public void run() {
				while(true) {
					clear();
					try {
						sleep(sleepTime);//休眠
					} catch (Exception e) {
					}
				}
			}
		}.start();
	}

	/**
	 * 获取验证码图片
	 * @return 返回base64图片及链接码
	 */
	@Override
	public MsgEmity getImage() {
		VerifyCodeUtil verifyCodeUtil = new VerifyCodeUtil();
		VerifyCodeResult result = new VerifyCodeResult();
		VerifyCodeCach cache = new VerifyCodeCach();

		String sId = SequenceUtil.getSequence();//取流水号方式获取创建的验证码id,后续通过这个id来对比文字
		long dTime = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));//获取秒数
		
		result.setsId(sId);
		result.setsImage(verifyCodeUtil.getImageBase64());//提供给请求方的信息中只有编号和图片、创建时间

		cache.setsId(sId);
		cache.setsTxt(verifyCodeUtil.getText().toUpperCase());//保留在缓存中的信息只有编号和文字、创建时间,转换成全大写便于对比
		cache.setdTime(dTime);
		
		cachMap.put(sId, cache);//添加缓存
		
		return MsgEmity.success(result, "创建验证码成功");
	}
	
	/**
	 * 判断提交的验证码是否符合
	 * @param sId 请求编号
	 * @param sUserTxt 提交验证的文字
	 * @return
	 */
	@Override
	public MsgEmity check(String sId, String sUserTxt) {
		if (null == sId || "".equals(sId)) {
			return MsgEmity.err(8001, "验证码编号参数为空");
		}
		
		if (null == sUserTxt || "".equals(sUserTxt)) {
			return MsgEmity.err(8002, "验证码参数为空");
		}
		
		VerifyCodeCach cache = cachMap.get(sId);
		if (null == cache) {
			return MsgEmity.err(8003, "未找到验证码信息,可能已经过期");
		}
		
		if (!sUserTxt.trim().toUpperCase().equals(cache.getsTxt())) {
			return MsgEmity.err(8004, "验证码不一致");
		}
		
		return MsgEmity.success(8999, "验证码一致");
	}
	
	/**
	 * 清理缓存
	 */
	private MsgEmity clear() {
		if (null == cachMap || cachMap.size() < 1) {
			return new MsgEmity(true, "释放成功", "本身没有这个缓存");
		}
		
		long dNow = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));//获取秒数
		
		//--循环检查哪些已经超过了时间点--//
		List<String> list = new ArrayList<String>();
		for (VerifyCodeCach verifyCodeInfo : cachMap.values()) {
			if ((dNow - verifyCodeInfo.getdTime()) < timeout) {
				continue;
			}
			
			list.add(verifyCodeInfo.getsId());//超期
		}
		
		for (String string : list) {
			cachMap.remove(string);
		}
		
		Log.debug("释放", list.size(), "个图片验证码信息");
		
		return new MsgEmity(true, "释放成功", new StringBuilder("释放数:").append(list.size()).toString());
	}
	
}
